package com.liuya.db.script;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;

import bsh.EvalError;
import bsh.Interpreter;
import com.liuya.safe.model.SafeUser;
import com.liuya.entitle.UserCategoryTestResult;
import com.liuya.safe.util.Constants;
import com.liuya.safe.policy.service.QueryManagerService;

public class UserCategory extends AbstractPolicy implements Script {

	public String getRule() {
		StringBuffer buff = new StringBuffer();
		if (isRawScript()) {
			buff.append(getRawScript().toScript()).append("\n");
		} else {
			buff.append("return ").append(getExprGroup().toScript()).append(";\n");
		}
		return buff.toString();
	}

	public String toScript() {
		if (getScript() == null) {

			StringBuffer buff = new StringBuffer();
			buff.append("java.util.Map " + Constants.VARIABLE_MAP + " = new java.util.HashMap();\n");
			int count = getDefineVaribles().size();
			for (int i = 0; i < count; i++) {
				DefineVariable defineVariable = (DefineVariable) getDefineVaribles().get(i);
				if (defineVariable instanceof QueryRef) {
					QueryRef queryRef = (QueryRef) defineVariable;
					if (getExprGroup().isUsedByInExprOrNotInExpr(queryRef.getVariableName())) {
						buff.append(queryRef.toScript(true));
					} else {
						buff.append(queryRef.toScript(false));
					}
				} else {
					buff.append(defineVariable.toScript());
				}
				buff.append(Constants.VARIABLE_MAP + ".put( \"" + defineVariable.getVariableName() + "\", " + defineVariable.getVariableName() + ");\n");
			}
			buff.append("\n");
			// return values is "doesUserCategoryContain"
			String doesUserCategoryContain = Constants.DOES_USER_CATEGORY_CONTAIN;
			if (isRawScript()) {
				buff.append(getRawScript().toScript() + ";\n");
				int index = buff.indexOf("return");
				if (index >= 0) {
					buff.replace(index, index + 6, " boolean " + doesUserCategoryContain + " = ");
					buff.append(";\n");
				} /*
				 * else { buff.append(" boolean " + doesUserCategoryContain +
				 * " = false;"); }
				 */
			} else {
				buff.append(" boolean ").append(doesUserCategoryContain).append(" = ( ").append(getExprGroup().toScript()).append(" ); \n");
			}

			setScript(buff.toString());
		}

		return getScript();
	}

	public UserCategoryTestResult test(SafeUser user, Map context, QueryManagerService queryManager) {
		UserCategoryTestResult result = new UserCategoryTestResult();
		Interpreter interpreter = new Interpreter();
		String script = toScript();
		try {
			eval(interpreter, user, context, queryManager);
			Boolean contain = (Boolean) interpreter.get(Constants.DOES_USER_CATEGORY_CONTAIN);
			Map variableMap = (Map) interpreter.get(Constants.VARIABLE_MAP);
			result.setValid(contain.booleanValue());
			result.setFailed(false);
			result.setScript(script);
			result.setVariableMap(variableMap);
		} catch (EvalError e) {
			result.setFailed(true);
			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			e.printStackTrace(pw);
			result.setErrorMessage(sw.toString());
			// result.setErrorMessage(StringUtil.getEvalError(e.getMessage()));
			result.setScript(script);
		}
		return result;
	}

	private void eval(Interpreter interpreter, SafeUser user, Map context, QueryManagerService queryManager) throws EvalError {
		String script = toScript();
		// Set variables
		interpreter.set(Constants.USER_KEY, user);
		interpreter.set(Constants.CONTEXT, context);
		interpreter.set(Constants.QUERY_MANAGER, queryManager);

		java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm");
		interpreter.set(Constants.SIMPLE_DATE_FORMAT, format);
		// eval the rule
		interpreter.eval(script);
	}
}